﻿
function pfRequestSuccess(success) {
    return function (data, textStatus, jqXHR) {
        if (data == "loginout") {
            window.location.href = "/Login/Login";
            return;
        }
        if (success) {
            success(data, textStatus, jqXHR);
        } else {
            if (data && data.Message) {
                alert(data.Message);
            }
        }
    };
}

/*
*分页组件，来自sapar项目
*/
jQuery.fn.pagination = function (maxentries, opts) {
    opts = jQuery.extend({
        items_per_page: 10, // 每页显示多少条记录
        current_page: 0,      //当前页码
        num_display_entries: 4, // 中间显示页码的个数
        num_edge_entries: 2, // 末尾显示页码的个数
        link_to: "javascript:;",         //页码点击后的链接
        prev_text: "&lt;&nbsp;上一页",   //上一页的文字
        next_text: "下一页&nbsp;&gt;",	   //下一页的文字
        ellipse_text: "...",  //页码之间的省略号
        display_msg: true, // 是否显示记录信息
        prev_show_always: true, //是否总是显示最前页
        next_show_always: true,//是否总是显示最后页
        setPageNo: false,//是否显示跳转第几页
        callback: function () {
            return false;
        } // 回调函数
    }, opts || {});

    return this.each(function () {
        // 总页数
        function numPages() {
            return Math.ceil(maxentries / opts.items_per_page);
        }
        /**
		 * 计算页码
		 */
        function getInterval() {
            var ne_half = Math.ceil(opts.num_display_entries / 2);
            var np = numPages();
            var upper_limit = np - opts.num_display_entries;
            var start = current_page > ne_half ? Math.max(Math.min(current_page
									- ne_half, upper_limit), 0) : 0;
            var end = current_page > ne_half ? Math.min(current_page + ne_half,
					np) : Math.min(opts.num_display_entries, np);
            return [start, end];
        }

        /**
		 * 点击事件
		 */
        function pageSelected(page_id, evt) {
            var page_id = parseInt(page_id);
            current_page = page_id;
            drawLinks();
            var continuePropagation = opts.callback(page_id, panel);
            if (!continuePropagation) {
                if (evt.stopPropagation) {
                    evt.stopPropagation();
                } else {
                    evt.cancelBubble = true;
                }
            }
            return continuePropagation;
        }

        /**
		 * 链接
		 */
        function drawLinks() {
            panel.empty();
            $pagin.empty();
            panel.append($pagin);
            var interval = getInterval();
            var np = numPages();
            var getClickHandler = function (page_id) {
                return function (evt) {
                    return pageSelected(page_id, evt);
                }
            }
            var appendItem = function (page_id, appendopts) {
                page_id = page_id < 0 ? 0 : (page_id < np ? page_id : np - 1);
                appendopts = jQuery.extend({
                    text: page_id + 1,
                    classes: ""
                }, appendopts || {});
                if (page_id == current_page) {
                    var lnk = $("<span class='current'>" + (appendopts.text)
							+ "</span>");
                } else {
                    var lnk = $("<a>" + (appendopts.text) + "</a>").bind(
							"click", getClickHandler(page_id)).attr('href',
							opts.link_to.replace(/__id__/, page_id));

                }
                if (appendopts.classes) {
                    lnk.addClass(appendopts.classes);
                }
                $pagin.append(lnk);
            }
            // 上一页
            if (opts.prev_text && (current_page > 0 || opts.prev_show_always)) {
                appendItem(current_page - 1, {
                    text: opts.prev_text,
                    classes: "prev"
                });
            }
            // 点点点
            if (interval[0] > 0 && opts.num_edge_entries > 0) {
                var end = Math.min(opts.num_edge_entries, interval[0]);
                for (var i = 0; i < end; i++) {
                    appendItem(i);
                }
                if (opts.num_edge_entries < interval[0] && opts.ellipse_text) {
                    jQuery("<span>" + opts.ellipse_text + "</span>")
							.appendTo($pagin);
                }
            }
            // 中间的页码
            for (var i = interval[0]; i < interval[1]; i++) {
                appendItem(i);
            }
            // 最后的页码
            if (interval[1] < np && opts.num_edge_entries > 0) {
                if (np - opts.num_edge_entries > interval[1]
						&& opts.ellipse_text) {
                    jQuery("<span>" + opts.ellipse_text + "</span>")
							.appendTo($pagin);
                }
                var begin = Math.max(np - opts.num_edge_entries, interval[1]);
                for (var i = begin; i < np; i++) {
                    appendItem(i);
                }

            }
            // 下一页
            if (opts.next_text
					&& (current_page < np - 1 || opts.next_show_always)) {
                appendItem(current_page + 1, {
                    text: opts.next_text,
                    classes: "next"
                });
            }
            // 记录显示
            if (opts.display_msg) {
                if (!maxentries) {
                    panel
						.append('<div class="pxofy">暂时无数据可以显示</div>');
                } else {
                    panel
                            .append('<div class="pxofy">显示第&nbsp;'
                                    + ((current_page * opts.items_per_page) + 1)
                                    + '&nbsp;条到&nbsp;'
                                    + (((current_page + 1) * opts.items_per_page) > maxentries
                                            ? maxentries
                                            : ((current_page + 1) * opts.items_per_page))
                                    + '&nbsp;条记录，总共&nbsp;' + maxentries + '&nbsp;条</div>');
                }
            }
            //设置跳到第几页
            if (opts.setPageNo) {
                $("<div class='goto'><span class='text'>转到第</span><input type='text'/><span class='page'>页</span><a href='javascript:;'>转</a></div>").insertBefore($pagin);
            }
        }

        // 当前页
        var current_page = opts.current_page;
        maxentries = (maxentries < 0) ? 0 : maxentries;
        opts.items_per_page = (!opts.items_per_page || opts.items_per_page < 0)
				? 1
				: opts.items_per_page;
        var panel = jQuery(this),
			$pagin = $('<div class="pagin-list"></div>');


        this.selectPage = function (page_id) {
            pageSelected(page_id);
        }
        this.prevPage = function () {
            if (current_page > 0) {
                pageSelected(current_page - 1);
                return true;
            } else {
                return false;
            }
        }
        this.nextPage = function () {
            if (current_page < numPages() - 1) {
                pageSelected(current_page + 1);
                return true;
            } else {
                return false;
            }
        }

        if (maxentries == 0) {
            panel.append('<span class="current prev">' + opts.prev_text + '</span><span class="current next">' + opts.next_text + '</span><div class="pxofy">暂时无数据可以显示</div>');
        } else {
            drawLinks();
        }
        $(this).find(".goto a").on("click", function (evt) {
            var setPageNo = $(this).parent().find("input").val();
            if (setPageNo != null && setPageNo != "" && setPageNo > 0 && setPageNo <= numPages()) {
                pageSelected(setPageNo - 1, evt);
            }
        });
    });
};//这里有了分号,否则有问题--wxj20180511


/*
* table组件扩展
* opts属性说明：
* button 自定义按钮，数组，如 [{text:,action:},'excel']
* selectMode:0不能选择 1单选 2多选,默认0,我增加的属性--benjamin
* rowDrag:bool 行可拖动排序--benjamin20190430
*/
jQuery.fn.pfTable = function (opts) {//设置DataTables组件的一些属性,要先引用相关资源--wxj20180515
    var me = this;
    var $pfTable = me;
    $pfTable.addClass('stripe');//当bAutoWidth为false时，有奇偶行样式(多了display这个class名)，但当为true时display这个class名没有加进入，原因未明.不过stripe也是DataTables自带样式，利用了--wxj20180830
    var result = {};
    result.tableApi = null;

    opts = opts || {};
    var hasSummary = false;
    var paginationOpts = null;
    var showPagination = opts.showPagination !== false;
    var selectMode = opts.selectMode || 0;
    var selectable = selectMode !== 0;
    var rowDrag = opts.rowDrag || false;//行可拖动排序,其实全部可拖也没什么影响--benjamin20190430
    //if (opts.pagination !== null && opts.pagination !== undefined) {
    //    paginationOpts = jQuery.extend({
    //        id: '',
    //        pageIndex: 0,
    //        pageSize: 10
    //    }, opts.pagination || {});
    //    delete opts.pagination;
    //    //showPagination =true;
    //}
    if (showPagination) {
        paginationOpts = jQuery.extend({
            id: $pfTable[0].id + '-pagin',
            pageIndex: 0,
            pageSize: 10
        }, opts.pagination || {});
        delete opts.pagination;
        //showPagination =true;
        if ($('#' + paginationOpts.id).length < 1) {
            $pfTable.after($('<div id="' + paginationOpts.id + '" class="pagination"></div>'));
        }
    }
    var _url = '';//调用loadUrl()时赋值(不包含pageIndex和pageSize参数)
    var _lastSort = '';//因为每次draw都触发order,所以自行判断
    var _lastFilterValue = '';
    //var privateObj = {};//私有变量
    var userLoadOpts = {};//用户调用loadUrl方法后需要保存的参数--benjamin20190419

    function bindCellClick() {
        for (var i in opts.onCellClick) {
            if (opts.onCellClick.hasOwnProperty(i)) {
                $pf.bindTableColumnClick(me, i, opts.onCellClick[i]);
            }
        }
    }
    var $headTable = {};

    //function exchangeRow(row1, row2) {//交换行
    //    var data = result.tableApi.row(row1).data();
    //    //var nextRow = rows.parent().children()[idx - 1];
    //    //var nextIds = result.tableApi.row(row2).index();
    //    var nextData = result.tableApi.row(row2).data();

    //    result.tableApi.row(row2).data(data);
    //    result.tableApi.row(row1).data(nextData);
    //}

    function fixSelect(body, cur, isSelected) {
        var tr = body.find('tr:eq(' + cur + ')');
        if (isSelected) {
            body.find('tr input.pf-row-select:eq(' + cur + ')').prop("checked", true);
            if (!tr.hasClass('selected')) {
                tr.addClass('selected');
            }
        } else {
            if (tr.hasClass('selected')) {
                tr.removeClass('selected');
            }
        }
    }
    //orders,如:[3,1,2]
    result.orderRow = function (sOrders) {
        var body = $pfTable.find('tbody');
        var maxIdx = body.find('tr').length - 1;
        if (sOrders.length !== (maxIdx + 1)) { return; }

        var orders = [];
        //for (var i = 0; i < sOrders.length; i++) {//输入参数有可能是string[],但需要的是int[]
        //    orders.push(typeof sOrders[i] === 'string' ? parseInt(sOrders[i]) : sOrders[i]);
        //}

        var oldRows = [];//[{selected:true,}]只存Data
        var selected = [];
        for (var i = 0; i <= maxIdx; i++) {
            //debugger;
            orders.push(typeof sOrders[i] === 'string' ? parseInt(sOrders[i]) : sOrders[i]);//输入参数有可能是string[],但需要的是int[]

            //var oi = typeof orders[i] === 'string' ? parseInt(orders[i]) : orders[i];
            var row = body.find('tr:eq(' + i + ')');
            if (orders[i] !== i) {//有变动才赋值,增加性能
                oldRows.push(result.tableApi.row(row[0]).data());
            } else {
                oldRows.push({});
            }
            if (selectable) {
                selected.push(row.find('input.pf-row-select').is(':checked'));
            }
        }
        for (var i = 0; i <= maxIdx; i++) {
            if (orders[i] !== i) {//有变动才赋值,增加性能
                var row = body.find('tr:eq(' + i + ')');
                result.tableApi.row(row[0]).data(
                    oldRows[orders[i]]
                );
                fixSelect(body, i, selected[orders[i]]);
            }
        }
        //for (var i = 0; i <= maxIdx; i++) {
        //    fixSelect(body,i, selected[i]);
        //}
    };
    function insertRow(srcRowIdx, dstRowIdx) {//src插到dst后面(如果这个方法维护麻烦,可以简接调用result.orderRow)
        var body = $pfTable.find('tbody');
        var srcRow = body.find('tr:eq(' + srcRowIdx + ')');
        var srcData = result.tableApi.row(srcRow[0]).data();
        var cur = srcRowIdx;
        var maxIdx = body.find('tr').length - 1;
        if (maxIdx < srcRowIdx) { return; }
        if (maxIdx < dstRowIdx) { dstRowIdx = maxIdx; }

        var selected = [];
        if (selectable) {//调换行时,选择的checkbox会清掉
            while (cur !== dstRowIdx) {
                var next = cur + (srcRowIdx > dstRowIdx ? -1 : 1);

                selected.push(body.find('tr input.pf-row-select:eq(' + cur + ')').is(':checked'));
                cur = next;
            }
            //for (var i = srcRowIdx; i <= dstRowIdx; i++) {
            //    selected.push(body.find('tr input.pf-row-select:eq(' + i + ')').is(':checked'));
            //}
        }
        selected.push(body.find('tr input.pf-row-select:eq(' + dstRowIdx + ')').is(':checked'));

        //console.info(selected);
        var cur = srcRowIdx;
        var i = 0;
        while (cur !== dstRowIdx) {
            var next = cur + (srcRowIdx > dstRowIdx ? -1 : 1);
            //下一行的数据填到cur行;
            result.tableApi.row(body.find('tr:eq(' + cur + ')')[0]).data(
                result.tableApi.row(body.find('tr:eq(' + next + ')')[0]).data()
            );
            if (selectable) {
                fixSelect(body, cur, selected[i + 1]);
                i++;
            }
            //console.info(cur);
            cur = next;
        }
        ////src填到dst行
        result.tableApi.row(body.find('tr:eq(' + dstRowIdx + ')')[0]).data(
            srcData
        );
        if (selectable) {
            fixSelect(body, dstRowIdx, selected[0]);
        }
    }
    var defaultDrawCallback = function () {
        //if (selectMode ===0) {
        //    me.find("tbody tr:odd").css("backgroundColor", "#eff6fa");//奇偶行样式,直接写在dom上优先级太高,选择行的样式都不生效，改为复写odd的背景色好了--wxj20180830
        //    me.find("tbody tr:even").css("backgroundColor", "white");
        //}
        me.find('tbody tr td.text-right').css("text-align", "right");//网上建议createdRow fnRowCallback (https://bbs.csdn.net/topics/391050901)

        //修复一个bug,当无数据时再变为有数据,这里虽然加了tfoot但初始化后没有去掉no-footer这个类导致多了个border-bottom(最好以后看看api对象时的foot属性是不是在destroy后并没有重置)
        if (hasSummary) {
            var $wrapper = $('#' + $pfTable[0].id + '_wrapper');
            var headInner = $wrapper.find('div.dataTables_scrollHeadInner table.dataTable');
            if (headInner.hasClass('no-footer')) {
                headInner.removeClass('no-footer');
            }
            var footInner = $wrapper.find('div.dataTables_scrollFootInner table.dataTable');
            if (footInner.hasClass('no-footer')) {
                footInner.removeClass('no-footer');
            }
            var scrollBody = $wrapper.find('div.dataTables_scrollBody table.dataTable');
            if (scrollBody.hasClass('no-footer')) {
                scrollBody.removeClass('no-footer');
            }
        }
        bindCellClick();

        if (selectable) {
            $headTable = $pfTable.parent().parent().find('.dataTables_scrollHead table');
            if ($headTable.attr('selectAllBinded') !== 'true') {
                $headTable.on('click', 'thead tr input.pf-row-select-all', function (e) {
                    $headTable.attr('selectAllBinded', 'true');
                    //alert(1);
                    $pf.stopPropagation(e);
                    //debugger;
                    var b = $(this).is(':checked');
                    //if (b === true) {

                    //}
                    var cbs = $pfTable.find('tbody tr input.pf-row-select');
                    cbs.each(function (index, element) {
                        var cb = $(element);
                        if (cb.is(':checked') !== b) { cb.click(); }
                    });

                });
            }
        }
        //搜索栏改为后端
        var searchF = $pfTable.parents('.dataTables_wrapper').find('.dataTables_filter input[type=search]');
        //debugger;
        searchF.unbind();
        searchF.change(function () {
            //alert(this.value);
            _lastFilterValue = this.value;
            //var lastFilterValue = this.value;
            var url = $pf.setUrlParams(_url, { filterValue: this.value });
            //var tmpOpts = jQuery.extend({ needSetLastFilterValue: true }, userLoadOpts);
            result.sysLoadUrl(url, { needSetLastFilterValue: true }
            //{
            //    //sysLoadSuccess: function (data) {
            //    //    //这里必需重新找组件,因为loadUrl时重新生成了search组件
            //    //    $pfTable.parents('.dataTables_wrapper').find('.dataTables_filter input[type=search]')
            //    //        .val(lastFilterValue);//因为loadUrl是页面共用的,理应把过滤器的值清掉,所以这里要重新赋值
            //    //    _lastFilterValue = lastFilterValue;
            //    //    if (typeof privateObj.userLoadSuccess == 'function') {//complete回调一般后续使用data更新其它dom
            //    //        privateObj.userLoadSuccess(data);
            //    //    }
            //    //}
            //}
            );

            //不用下面ajax方式的原因是,如果后面无数据时返回了false,DataTable会报错
            //var url = result.tableApi.ajax.url($pf.setUrlParams(_url, { PageSize: opts.pagination.pageSize, PageIndex: 0, sort: _lastSort ,filterValue:this.value}));
            //url.load(function (data) {
            //    ////debugger;
            //    //if (selectMode === 2) {
            //    //    $headTable.find('thead tr input.pf-row-select-all').prop("checked", false);
            //    //}
            //    bindPaging(data.total, 0);
            //    //searchF.val(_lastFilterValue);
            //});
        });

        if (rowDrag) {
            function allowDrop(ev) {
                ev.preventDefault();
            }
            function drag(ev) {
                var idx = $(ev.target).parent().find('tr').index(ev.target);
                //ev.originalEvent.dataTransfer.setData("dragRowIdx", idx);
                ev.originalEvent.dataTransfer.setData("Text", idx.toString());//ie中,第一个参数必需为Text,第二个必需为String
            }
            function drop(ev) {
                ev.preventDefault();
                //var dragRowIdx = parseInt(ev.originalEvent.dataTransfer.getData("dragRowIdx"));
                var dragRowIdx = parseInt(ev.originalEvent.dataTransfer.getData("Text"));
                var dragRow = $pfTable.find('tbody tr:eq(' + dragRowIdx + ')');
                var targetRow = $(ev.target).parent('tr');
                var targetRowIdx = targetRow.parent().find('tr').index(targetRow);
                if (dragRowIdx === targetRowIdx) {
                    //console.info('相同');
                } else {
                    insertRow(dragRowIdx, targetRowIdx);
                    //exchangeRow(dragRow, targetRow);
                }
            }
            $pfTable.find('tbody tr').attr('draggable', true)
            .on('dragover', allowDrop)
            .on('dragstart', drag)
            .on('drop', drop);
        }
    };
    //debugger;
    var drawCallback = null;
    if (typeof opts.drawCallback == 'function') {
        var userDrawCallback = opts.drawCallback;
        drawCallback = function () {
            var drawMe = this;
            defaultDrawCallback();
            userDrawCallback.call(drawMe);
        }
        delete opts.drawCallback;
    } else {
        drawCallback = defaultDrawCallback;
    }

    //var buttons = $pf.getTableToolbar(opts);
    var buttons = [];
    var excelBtn = {
        text: '导出Excel', action: function (event) {
            var url = _url;
            if (url[0] !== '/') {//如果是相对地址,要转为绝对地址
                url = window.location.pathname.replace(/[^/]*$/, url)
            }
            $pf.exporter({
                title: null,
                dataAction: url
            })
            .download($(event.currentTarget).attr("suffix"))
            ;
        }
    };
    var addBtn = {
        text: '新增', alwayShow: true, action: function (event) {
            $pfTable.trigger('tbar.add');
        }
    };
    var editBtn = {
        text: '修改', action: function (event) {
            var rows = result.getSelectedRows();
            if (rows.length === 1) {
                $pfTable.trigger('tbar.edit', [result.tableApi.row(rows[0]).data()]);
            } else {
                $pf.warningPopups("请选择一行");
            }

            //var data = result.tableApi.row('.selected').data();
            //if (data === null || data === undefined){
            //    $pf.warningPopups("请选择一行"); return;
            //}
            //$pfTable.trigger('tbar.edit', [data]);
        }
    };
    var deleteBtn = {
        text: '删除', action: function (event) {
            var data = [];
            var rows = result.getSelectedRows();
            if (rows.length > 0) {
                for (var i = 0; i < rows.length; i++) {
                    data.push(result.tableApi.row(rows[i]).data());
                }
                $pf.confirmPopups('确定删除吗?' + (data.length > 1 ? '数量:' + data.length : ''), function () {
                    $pfTable.trigger('tbar.delete', [data]);//删除时应该是可以多选的,所以data是数组
                });
            } else {
                $pf.warningPopups("请选择需要删除的行");
            }

            //var data = result.tableApi.row('.selected').data();
            //if (data === null || data === undefined) {
            //    $pf.warningPopups("请选择一行"); return;
            //}
            //$pf.confirmPopups('确定删除吗?', function () {
            //    $pfTable.trigger('tbar.delete', [data]);
            //});
        }
    };
    var setVisibleColumnBtn = {
        text: '设置显示列', action: function (event) {
            var url = _url;
            if (url[0] !== '/') {//如果是相对地址,要转为绝对地址
                url = window.location.pathname.replace(/[^/]*$/, url)
            }
            $pf.setVisibleColumnPopups({ dataAction: url });
            //$pf.exporter({
            //    title: null,
            //    dataAction: url
            //})
            //.download($(event.currentTarget).attr("suffix"))
            //;
        }
    };
    //debugger;
    if (opts.buttons instanceof Array) {
        for (var i = 0; i < opts.buttons.length; i++) {
            switch (opts.buttons[i].Name) {
                case 'Export':
                case 'excel':
                    buttons.push(excelBtn);
                    break;
                case 'Add':
                    buttons.push(addBtn);
                    break;
                case 'Edit':
                    buttons.push(editBtn);
                    break;
                case 'Delete':
                    deleteBtn.text = opts.buttons[i].Text;
                    buttons.push(deleteBtn);
                    break;
                case 'SetVisibleColumn':
                    buttons.push(setVisibleColumnBtn);
                    break;
                default:
                    (function (name, text, alwayShow) {//注意action会有作用域的问题
                        buttons.push({
                            text: text,
                            alwayShow: alwayShow,
                            action: function (event) {
                                //debugger;
                                var data = [];
                                var rows = result.getSelectedRows();
                                if (rows.length > 0) {
                                    for (var i = 0; i < rows.length; i++) {
                                        data.push(result.tableApi.row(rows[i]).data());
                                    }
                                }
                                //var data = result.tableApi.row('.selected').data();
                                $pfTable.trigger('tbar.' + name, [data]);
                            }
                        });
                    }(opts.buttons[i].Name, opts.buttons[i].Text, opts.buttons[i].AlwayShow));
                    //var name = opts.buttons[i].Name;
                    //buttons.push({
                    //    text: opts.buttons[i].Text,
                    //    action: function (event) {
                    //        //debugger;
                    //        var data = [];
                    //        var rows = result.getSelectedRows();
                    //        if (rows.length > 0) {
                    //            for (var i = 0; i < rows.length; i++) {
                    //                data.push(result.tableApi.row(rows[i]).data());
                    //            }
                    //        }
                    //        //var data = result.tableApi.row('.selected').data();
                    //        $pfTable.trigger('tbar.' + name, [data]);
                    //    }
                    //});
                    break;
            }
        }
        //delete opts.buttons;
    } else {
        //buttons = [excelBtn];
        buttons = [];
    }
    delete opts.buttons;
    //debugger;
    var defaultOpts = jQuery.extend({
        "language": {
            search: "搜索:",
            sZeroRecords: "没有找到匹配的记录"
        },
        destroy: true,
        pagination: paginationOpts,
        paging: false,
        info: false,
        //scrollY: true,
        scrollX: true,
        order: [],
        drawCallback: drawCallback
    }, opts || {});
    if (buttons.length > 0) { defaultOpts.buttons = buttons; defaultOpts.dom = 'Bfrtip'; }

    function newOpts() {
        var r = jQuery.extend({}, defaultOpts);
        if (r.order instanceof Array) {
            r.order = r.order.slice(0);//数组型的成员要这样才不会因opts改变而改变
        }
        return r;
    }
    opts = newOpts();

    function bindPaging(total, current) {//绑定分页组件
        //if (showPagination) {
        paging = $('#' + opts.pagination.id).pagination(total, {
            items_per_page: opts.pagination.pageSize,
            current_page: current,
            callback: function (page) {
                opts.pagination.pageIndex = page;
                //var url = result.tableApi.ajax.url(_url + "&PageSize=" + opts.pagination.pageSize + "&PageIndex=" + page + "&sort=" + _lastSort);
                var url = result.tableApi.ajax.url($pf.setUrlParams(_url, { PageSize: opts.pagination.pageSize, PageIndex: page, sort: _lastSort, filterValue: _lastFilterValue }));
                url.load(function () {
                    //if (selectMode===2) {
                    //    $headTable.find('thead tr input.pf-row-select-all').prop("checked", false);
                    //}
                    bindPaging(total, page);
                });
            },
            display_msg: true,
            setPageNo: true
        });
        if (selectMode === 2) {
            $headTable.find('thead tr input.pf-row-select-all').prop("checked", false);

            if (opts.fixedColumns !== undefined && opts.fixedColumns !== false) {//如果有锁定列时
                $pfTable.parent().parent().parent().find('.DTFC_LeftWrapper .DTFC_LeftHeadWrapper table.dataTable tr th input.pf-row-select-all').prop("checked", false);
            }
        }
        if (!$pf.stringIsNullOrWhiteSpace(_lastFilterValue)) {
            var searchF = $pfTable.parents('.dataTables_wrapper').find('.dataTables_filter input[type=search]');
            searchF.val(_lastFilterValue);
        }
        //}
        //bindCellClick();
    }
    result.loadCurrentPage = function (loadOpts) {//刷新当前页(编辑数据后使用)
        var url = result.tableApi.ajax.url($pf.setUrlParams(_url, { PageSize: opts.pagination.pageSize, PageIndex: opts.pagination.pageIndex, sort: _lastSort, filterValue: _lastFilterValue, random: Math.random() }));
        url.load(function (data) {
            if (loadOpts !== null && loadOpts !== undefined && typeof loadOpts.success == 'function') {
                loadOpts.success(data);
            }
            bindPaging(data.total, opts.pagination.pageIndex);
        });
    };
    result.getSelectedRows = function () {
        return $pfTable.find('tbody tr.selected');
    };
    function getHeaderTR(lists, maxDepth, currentDepth) {
        if (currentDepth == null || currentDepth == undefined) { currentDepth = 1; }
        var writer = "";
        if (lists != null) {
            //显示下一层
            var next = [];
            //显示头
            for (var idx = 0; idx < lists.length; idx++) {
                var i = lists[idx];
                writer += getHeaderTD(i, maxDepth, currentDepth);

                if (i.Children != null) {//下一层数据
                    for (var j = 0; j < i.Children.length; j++) {
                        next.push(i.Children[j]);
                    }
                }
            }

            if (next.length > 0) {
                writer += "</tr>";
                writer += "<tr>";
                writer += getHeaderTR(next, maxDepth, ++currentDepth);
            }
        }
        return writer;
    }
    function getHeaderTD(item, maxDepth, currentDepth) {
        var writer = "";
        var title = item.data || item.title;//合并列用中文,其它列要对应data
        //if (title === null || title === undefined || title === '') { return; }
        item._columnSpan = 1;
        item._rowSpan = 1;
        var style = "";
        //debugger;
        //if (item.Children != null && item.Children != undefined && item.Children.length > 1)
        if (item.Children != null && item.Children != undefined && item.Children.length > 0)//大于0才是对的--wxj20180906
        {
            item._columnSpan = $pf.getAllLeafCount(item);
        } else {
            style += "border-bottom: 1px solid #111;";//最后一个th加下加框--wxj20180716
            if (maxDepth > currentDepth) {
                item._rowSpan = maxDepth - currentDepth + 1;
            }
        }
        if (!$pf.stringIsNullOrWhiteSpace(item.width)) { style += "width=" + item.width + ";"; }
        if (!$pf.stringIsNullOrWhiteSpace(style)) { style = " style='" + style + "' "; }
        //if (!Visible) { style = "style=' display:none' "; }
        var attrs = "";
        if (item.data !== null && item.data !== undefined) { attrs += " field-name='" + item.data + "' "; }

        if (item.isSelectAllCol) {
            if (selectMode === 1) { title = "选择"; }
            else if (selectMode === 2) { title = "<input type='checkbox' class='pf-row-select-all' />全选"; }
        }
        writer += $pf.formatString("<th {1} {2} {3} {4}>{0}</th>", title, item._columnSpan > 1 ? ("colspan=" + item._columnSpan) : "", item._rowSpan > 1 ? ("rowspan=" + item._rowSpan) : "", style, attrs);

        return writer;
    }
    function setLastFilterValue() {
        //这里必需重新找组件,因为loadUrl时重新生成了search组件
        $pfTable.parents('.dataTables_wrapper').find('.dataTables_filter input[type=search]')
            .val(_lastFilterValue);//因为loadUrl是页面共用的,理应把过滤器的值清掉,所以这里要重新赋值
    }
    result._loadUrl = function (url, loadOpts) {
        var mescope = this;
        if ($('body').width() == 0) {//当在页面a中用异步tab加页面b的iframe时，如果页面b中有pfTable,parent的宽度是0，结果是表头和body都不是100%，表头靠左，body水平居中--wxj20181218
            //console.info('wait');
            setTimeout(function () {
                result._loadUrl.call(mescope, url, loadOpts);
            }, 100);
            return;
        }
        loadOpts = loadOpts || {};
        //var toUrl = url + "&PageIndex=0";        
        var toUrlParams = { PageIndex: 0 };
        if (showPagination) {
            //toUrl += "&PageSize=" + opts.pagination.pageSize;
            toUrlParams.PageSize = opts.pagination.pageSize;
        }
        toUrl = $pf.setUrlParams(url, toUrlParams);
        var layerIdx = layer.load('正在查询请稍候');
        $pf.post(toUrl, null, function (data) {
            //debugger;
            $pfTable = me;
            if (data && data.Result !== false && typeof data !== 'string') {//MvcMenuFilter拦截后直接返回了文字--wxj20181127
                if (result.tableApi !== null && data.columns !== null) {
                    //alert('destroy');
                    result.tableApi.destroy();
                    $(me).empty();
                }
                //debugger;
                //opts.pagination.url = url;
                _url = url;
                if (data.columns !== null || result.tableApi === null) {//列数据有更新时
                    opts = newOpts();
                    opts.data = data.data;
                    if (data.columns !== null) {
                        var treeColumn = { Children: data.columns };
                        //为了生成多表头,需要拼接<thead>
                        var thead = "<thead><tr>";
                        if (selectable) {
                            data.columns.splice(0, 0, {
                                isSelectAllCol: true,
                                orderable: false,
                                width: '15px',
                                Children: [],
                                render: function () {
                                    return '<input type="checkbox" class="pf-row-select"  />';
                                }
                            });
                        }

                        thead += getHeaderTR(data.columns, $pf.getDepth(treeColumn) - 1);
                        thead += "</tr></thead>";
                        //debugger;
                        $(thead).appendTo($pfTable);
                        //汇总信息
                        var foot = '';
                        hasSummary = false;

                        var columns = [];

                        $pf.eachLeaf(treeColumn, function (i) {
                            if (i.dataType === 'decimal' || i.dataType === 'int') {
                                if (i.className === null || i.className === undefined) { i.className = ''; }
                                i.className += ' text-right';
                                i.render = function (data, type, row) {
                                    return $pf.thousandth(data);
                                }
                            }
                            if (i.dataType === 'percent') {
                                //debugger;
                                if (i.className === null || i.className === undefined) { i.className = ''; }
                                i.className += ' text-right';
                                i.render = function (data, type, row) {
                                    return $pf.stringIsNullOrWhiteSpace(data) ? '' : ($pf.thousandth($pf.toFixed(data)) + ' %');
                                }
                            }
                            if (i.dataType === 'DateTime') {
                                i.render = function (data, type, row) {
                                    return $pf.formatTime(data, 'yyyy-MM-dd hh:mm:ss');
                                }
                            }
                            if (i.dataType === 'date') {
                                i.render = function (data, type, row) {
                                    return $pf.formatDate(data);
                                }
                            }
                            if (i.dataType === 'bool') {
                                i.render = function (data, type, row) {
                                    return data === true ? "是" : "否";
                                }
                            }

                            if (i.summary !== null && i.summary !== undefined) {
                                if (!hasSummary) {
                                    foot = foot.replace(/<th><\/th>$/, '<th style="text-align:right">Total:</th>');
                                }
                                hasSummary = true;
                                var h = typeof i.render === 'function' ? i.render(i.summary) : i.summary;
                                foot += '<th style="text-align:right">' + h + '</th>';
                            } else {
                                foot += '<th></th>';
                            }
                            columns.push(i);
                        });
                        opts.columns = columns;

                        if (hasSummary) {
                            $($('<tfoot>' +
                                    '<tr>' + foot +
                                    '</tr>' +
                                '</tfoot>')).appendTo($pfTable);

                        }
                        //bindEvent();
                        //alert('create with column');
                    }
                    else {
                        //alert('create without column');
                    }
                    result.tableApi = $pfTable.DataTable(opts);
                    //console.info($pfTable.width());
                    //console.info($pfTable.parent().width());
                    if ($pfTable.width() < $pfTable.parent().width()) {//默认自动调列宽。当table的宽度小于容器和分页器时，如果用自动，会变得很窄，所以设置为不自动，然后利用css设置宽度为100%

                        opts.bAutoWidth = false;
                        result.tableApi = $pfTable.DataTable(opts);

                    }
                    //console.info("bAutoWidth = " + opts.bAutoWidth);
                    //console.info($pfTable.width());
                    //console.info($pfTable.parent().width());
                    //console.info($('body').width());
                    //console.info('----------------');
                } else {//列数据无更新时
                    result.tableApi.clear();
                    for (var i = 0; i < data.data.length; i++) {
                        result.tableApi.row.add(data.data[i]);
                    }
                    //alert('reload rows');
                    result.tableApi.draw();
                }
                if (showPagination) {
                    opts.pagination.pageIndex = 0;
                    bindPaging(data.total, 0);//如果不重新绑定,总页数不会改变,当前页也不会置为0
                    $('#' + opts.pagination.id).show();
                }

                if (typeof loadOpts.success == 'function') {//complete回调一般后续使用data更新其它dom
                    loadOpts.success(data);
                    //privateObj.userLoadSuccess = loadOpts.success;
                }
                if (loadOpts.needSetLastFilterValue) {
                    setLastFilterValue();
                }
                //if (typeof loadOpts.sysLoadSuccess == 'function') {
                //    loadOpts.sysLoadSuccess(data);
                //}
                ////$('#' + opts.pagination.id).show();
            } else {

                if (result.tableApi !== null) {
                    result.tableApi.destroy();
                    $(me).empty();
                }
                var message = "没有数据";
                if (typeof data === 'string') { message = data; }
                else if (data && data.Message) { message = data.Message; }
                $(me).html('<thead><tr><th>提示</th></tr></thead><tbody><tr onclick="$pf.stopPropagation(arguments[0])"><td  onclick="$pf.stopPropagation(arguments[0])">' + message + '</td></tr></tbody>');
                var alwayBtns = [];
                //debugger;
                for (var i = 0; i < buttons.length; i++) {
                    if (buttons[i].alwayShow === true) {
                        alwayBtns.push(buttons[i]);
                    }
                }
                //debugger;
                var nullOpts = { paging: false, info: false, searching: false };
                if (alwayBtns.length > 0) { nullOpts.buttons = alwayBtns; nullOpts.dom = 'Bfrtip'; }
                result.tableApi = me.DataTable(nullOpts);
                if (showPagination) { $('#' + opts.pagination.id).hide(); }

            }
            if (layerIdx) { layer.close(layerIdx); }
            if (typeof loadOpts.complete == 'function') {//complete回调一般用于mask的状态控制,重新更新列宽等
                loadOpts.complete();
            }
        });
    };
    result.loadUrl = function (url, loadOpts) {//为了便于导出,url请用完整地址.load时更新分页组件的属性.不要想把批量上传的文件放这里，因为如果每次都上传文件会很慢的,也不要把hybhs拼接到url上(url太长也会报错),只能后台用session保存,然后传进来;loadOpts不应改为系统变量
        _lastFilterValue = '';
        userLoadOpts = loadOpts;
        result._loadUrl(url, loadOpts);
    };
    result.sysLoadUrl = function (url, loadOpts) {//Table内部使用
        loadOpts = jQuery.extend(loadOpts, userLoadOpts);
        result._loadUrl(url, loadOpts);
    };
    //debugger;
    if (selectMode == 1 || selectMode == 2) {
        selectRow = function (tr) {
            if (tr.hasClass('selected')) {
                tr.removeClass('selected');
                tr.find('input.pf-row-select').prop("checked", false);
            }
            else {
                if (selectMode == 1) {
                    var trs = result.tableApi.$('tr.selected');
                    var cbs = trs.find('input.pf-row-select');
                    cbs.prop("checked", false);
                    trs.removeClass('selected');
                }
                tr.addClass('selected');
                tr.find('input.pf-row-select').prop("checked", true);
            }
        }
        $pfTable.on('click', 'tbody tr input.pf-row-select', function (e) {
            $pf.stopPropagation(e);
            //debugger;
            var tr = $(this).parent().parent();
            var tempTb = tr.parent().parent();
            if (tempTb.attr('id') !== $pfTable.attr('id')) {//如果有锁定列时,点击锁定列时进入这里
                var idx = tr.parent().find('tr').index(tr);//行序号
                $pfTable.find('tbody tr:nth-child(' + (idx + 1) + ')').click();
                return;
            }

            if (opts.fixedColumns !== undefined && opts.fixedColumns !== false) {//如果有锁定列时,点击普通列进入这里
                var idx = tr.parent().find('tr').index(tr);//行序号
                //$pfTable.parent().parent().parent().find('.DTFC_LeftWrapper table.dataTable tr:nth-child(' + (idx + 1) + ') input.pf-row-select').prop("checked", false);
                selectRow($pfTable.parent().parent().parent().find('.DTFC_LeftWrapper .DTFC_LeftBodyWrapper table.dataTable tr:nth-child(' + (idx + 1) + ') '));
            }

            selectRow(tr);
            //if (tr.hasClass('selected')) {
            //    tr.removeClass('selected');
            //}
            //else {
            //    if (selectMode == 1) {
            //        var trs = result.tableApi.$('tr.selected');
            //        var cbs = trs.find('input.pf-row-select');
            //        cbs.prop("checked", false);
            //        trs.removeClass('selected');
            //    }
            //    tr.addClass('selected');
            //}
        });
        $pfTable.on('click', 'tbody tr', function (e) {
            $pf.stopPropagation(e);
            $(this).find('input.pf-row-select').click();
            //var cbs =$(this).find('input.pf-row-select');
            ////cbs.prop("checked", true);
            //cbs.click();
        });
    }

    var _isOrdering = false;
    $pfTable.on('order.dt', function (e) {//注意，这里的datatables原生排序事件不仅在点表头时会触发，draw后也会触发
        // This will show: "Ordering on column 1 (asc)", for example
        if (result.tableApi) {
            //debugger;
            $pf.stopPropagation(e);
            var order = result.tableApi.order();
            if (order.length > 0) {
                var sort = result.tableApi.column(order[0][0]).dataSrc() + "%20" + order[0][1];
                if (_lastSort === sort) { return; }
                if (_isOrdering === true) { return; }
                _isOrdering = true;
                //var url = _url + "&sort=" + sort;//当_url没有?号时直接加&会使地址错误--benjamin20190430
                var url = $pf.setUrlParams(_url, { sort: sort });

                if (showPagination) { url += "&PageSize=" + opts.pagination.pageSize + "&PageIndex=" + opts.pagination.pageIndex; }
                $pf.post(url, null, function (data) {
                    //$pf.post(getPagingUrl(), null, function (data) {
                    if (data && data.Result !== false) {
                        result.tableApi.clear();
                        for (var i = 0; i < data.data.length; i++) {
                            result.tableApi.row.add(data.data[i]);
                        }
                        opts.order = [[order[0][0], order[0][1]]];
                        result.tableApi.draw();
                        setLastFilterValue();//benjamin20190419
                        //result.tableApi.order([order[0], order[1]]);
                    }
                    _isOrdering = false;
                    _lastSort = sort;
                });
                //var param = $("#f1").serialize();
                //tableApi.loadUrl("GetData?" + param + "&sort=" + tableApi.tableApi.column(order[0]).dataSrc() + "%20" + order[0][1]);
            }
            //alert('Ordering on column ' + order[0][0] + ' (' + order[0][1] + ')');
            return false;
        }
        //$('#orderInfo').html('Ordering on column ' + order[0][0] + ' (' + order[0][1] + ')');
    });
    result.isRowSelectAll = function () {
        return $headTable.find('thead tr input.pf-row-select-all').is(':checked');
    };
    //result.rowMoveUp = function () {//已经实现拖放移动--benjamin20190429
    //    var rows = result.getSelectedRows();
    //    if (rows.length === 1) {
    //        //table.data().length
    //        var idx=result.tableApi.row(rows[0]).index();
    //        if (idx === 0) {
    //            $pf.warningPopups("第一行不能上移");
    //        }
    //        exchangeRow(rows[0], rows.parent().children()[idx - 1]);
    //        rows.find('input.pf-row-select').prop("checked", true);

    //        //var data = result.tableApi.row(rows[0]).data();
    //        //var nextRow = rows.parent().children()[idx - 1];
    //        //var nextIds = result.tableApi.row(nextRow).index();
    //        //var nextData = result.tableApi.row(nextRow).data();

    //        //result.tableApi.row(nextRow).data(data);
    //        //result.tableApi.row(rows[0]).data(nextData);
    //        ////alert(idx);
    //        ////alert(nextIds);
    //        ////$pfTable.trigger('tbar.edit', [result.tableApi.row(rows[0]).data()]);
    //    } else {
    //        $pf.warningPopups("请选择一行");
    //    }
    //};
    return result;
};
jQuery.fn.pfTreeTable = function (opts) {
    var me = this;
    //var selector = me.selector;
    me.addClass('pfTreeGrid');
    var _url = '';//调用loadUrl()时赋值(不包含pageIndex和pageSize参数)
    var _colIdxs = [];//保存多表头的列信息,为了不用多次循环生成,有改变时更新

    function bindCellClick() {
        for (var i in opts.onCellClick) {
            if (opts.onCellClick.hasOwnProperty(i)) {
                //$pf.bindTableColumnClick(me.selector, i, opts.onCellClick[i]);
                var idx = _colIdxs.indexOf(i);
                //debugger;
                if (idx !== null && idx !== undefined) {
                    var $cell = me.find(' tbody tr td:nth-child(' + (idx + 1) + ')');
                    $cell.unbind('click', opts.onCellClick[i]);
                    $cell.bind('click', opts.onCellClick[i]);
                    $cell.css('textDecoration', 'underline');
                    $cell.css('cursor', 'pointer');
                }
            }
        }
    }
    var defaultDrawCallback = function () {
        bindCellClick();
        //alert(1);
    };
    //debugger;
    var drawCallback = null;
    if (typeof opts.drawCallback == 'function') {
        var userDrawCallback = opts.drawCallback;
        drawCallback = function () {
            defaultDrawCallback();
            userDrawCallback();
        }
        delete opts.drawCallback;
    } else {
        drawCallback = defaultDrawCallback;
    }
    var defaultOpts = jQuery.extend({

    }, opts || {});
    var opts = jQuery.extend({}, defaultOpts);
    var result = {};
    function createTr(list, pId) {
        var rowId = 1;
        if (pId !== undefined) { rowId = pId + 1; }
        var result = [];
        for (var i = 0; i < list.length; i++) {
            var row = { id: rowId, pId: pId, data: list[i].Data };
            result.push(row);
            if (list[i].Children) {
                var c = createTr(list[i].Children, rowId);
                for (var j = 0; j < c.length; j++) {
                    result.push(c[j]);
                }
                rowId = rowId + c.length;
            }
            rowId++;
        }
        return result;
    }
    function createTd(column, value) {
        var style = '';
        if ((column.dataType === 'decimal' || column.dataType === 'int') && value !== null && value !== undefined) {
            value = $pf.thousandth(value);
            style += 'text-align:right;padding-right: 9px;';
            //style = 'style="text-align:right;padding-right: 9px"';
        }
        if (column.visible === false) { style += 'display:none;'; }
        if (style.length > 0) { style = 'style="' + style + '"'; }
        if (value === null) { return '<td ' + style + '></td>'; }
        return '<td ' + style + '>' + value + '</td>';
    }
    result.loadData = function (data, loadOpts) {//当json的深度和行数非常大时,不能通过post来实现,只能用iframe放入子页面的方法
        loadOpts = loadOpts || {};
        //debugger;
        //if (data !== null && data !== undefined && typeof data === 'string') {//很复杂的JSON时,后端手动序列化为str后返回
        //    data = JSON.parse(data);
        //}
        var $body = me.find('tbody');
        if ($body.length === 0) { me.append('<tbody></tbody>'); $body = me.find('tbody'); }
        $body.html('');
        var $head = me.find('thead');
        if ($head.length === 0) { me.prepend('<thead></thead>'); $head = me.find('thead'); }
        $head.html('');
        if (data && data.Result !== false) {
            if (data.data) {
                var trs = createTr(data.data);
                var h = '';
                for (var i = 0; i < trs.length; i++) {
                    var tr = trs[i];
                    h += '<tr class="treegrid-' + tr.id + ' '
                        + (tr.pId == null ? '' : ('treegrid-parent-' + tr.pId))
                        + '">';
                    if (data.columns) {
                        for (var j = 0; j < data.columns.length; j++) {
                            var value = tr.data[data.columns[j].data];
                            h += createTd(data.columns[j], value);
                            //var style = '';
                            //if ((data.columns[j].dataType === 'decimal' || data.columns[j].dataType === 'int') && value !== null && value !== undefined) {
                            //    value = $pf.thousandth(value);
                            //    style = 'style="text-align:right;padding-right: 9px"';
                            //}
                            //h += '<td ' + style + '>' + value + '</td>';
                        }
                    } else {
                        for (var j in tr.data) {
                            if (tr.data.hasOwnProperty(j)) {
                                h += '<td>' + tr.data[j] + '</td>';
                            }
                        }
                    }
                    h += '</tr>';
                }
                $body.append(h);
            }
            if (data.columns) {
                var h = '<tr>';
                for (var j = 0; j < data.columns.length; j++) {
                    h += '<th>' + (data.columns[j].title || data.columns[j].data) + '</th>';
                }
                h += '</tr>';
                $head.append(h);
            }
            if (typeof loadOpts.success == 'function') {
                loadOpts.success(data);
            }
        } else {
            $head.append('<tr><th>提示</th></tr>');
            var message = "没有数据";
            if (data && data.Message) { message = data.Message; }
            $body.append('<tr><td>' + message + '</td></tr>');
        }

        me.treegrid(opts);
        $body.find("tr:odd").css("backgroundColor", "#eff6fa");//奇偶行样式
        $body.find("tr:even").css("backgroundColor", "white");
        if (typeof loadOpts.complete == 'function') {
            loadOpts.complete(data);
        }
    };
    result.loadUrl = function (url, loadOpts) {
        loadOpts = loadOpts || {};
        $.post(url, null, function (data) {
            result.loadData(data, loadOpts);
            _url = url;
        });
    };
    var layerIdx = null;
    result.loadChildNode = function (td, url, loadOpts) {//单层加载(pfGrid)
        var td = $(td);
        var tr = td.parent('tr');
        var level = tr.attr('level');
        var expanded = tr.attr('expanded');
        var loaded = tr.attr('loaded');
        var me = this;
        loadOpts = loadOpts || {};
        if (//expanded === 'expanded' &&
            loaded !== 'loaded') {//pfUtils.js里展开了
            //debugger;
            layerIdx = layer.load('正在查询请稍候');
            $.post(url, null, function (data) {
                if (data && data.Result !== false) {
                    if (data.data) {
                        var h = '';
                        var iLevel = null;
                        if (level !== null && level !== undefined) { iLevel = parseInt(level) + 1; }

                        for (var i = 0; i < data.data.length; i++) {
                            var trData = data.data[i].Data;
                            var ij = 0;
                            h += '<tr class="pfGridItem" level="' + iLevel + '" >';

                            //就根据后台的columns顺序来生成好了,因为打印方法要使用,所以后台反正要写columns的,以后台为准
                            $pf.eachLeaf({ Children: data.columns }, function (c) {
                                var txt = trData[c.data];
                                if (txt === undefined) { txt = ''; }
                                if (ij === 0) {
                                    var linearea = '';
                                    for (var k = 0; k < iLevel; k++) { linearea += '<div class="linearea"></div>'; }
                                    h += '<td>' + linearea + '<div class="hitarea hitarea-closed"></div>' + txt + '</td>';
                                } else {
                                    h += createTd(c, txt);
                                }
                                ij++;
                            });

                            h += '</tr>';
                        }
                        if (h !== '') { $(tr).after(h); }
                        drawCallback();
                    }
                }
                tr.attr('loaded', 'loaded');
                if (layerIdx) { layer.close(layerIdx); }
                if (typeof loadOpts.complete == 'function') {
                    loadOpts.complete(data);
                }
                //result.loadData(data, loadOpts);
                //_url = url;
            });
        }
    };
    result.setUrl = function (url) {
        _url = url;

    };
    //result.initTable = function () {//用页面上已生成tr节点的完整Table来初始化
    //    $(selector).treegrid(opts);
    //    //$(selector + ' tbody tr td:nth-child(1)').click(function (e) { $pf.expandTree(this); });//展开事件
    //    $(selector).on('click', 'tbody tr td:nth-child(1)', function (e) {//注意索引是从1开始的
    //        $pf.expandTree(this);
    //    });
    //};
    result.exportExcel = function (event) {
        //alert(1);
        //debugger;
        var url = _url;
        if (url[0] !== '/') {//如果是相对地址,要转为绝对地址
            url = window.location.pathname.replace(/[^/]*$/, url)
        }
        //debugger;
        $pf.exporter({
            title: null,
            dataAction: url
        })
        .download($(event.currentTarget).attr("suffix"))
        ;
    };
    //工具栏
    //debugger;
    var buttons = [];
    var excelBtn = {
        text: '导出Excel', action: result.exportExcel
    };
    if (opts.buttons instanceof Array) {
        for (var i = 0; i < opts.buttons.length; i++) {
            switch (opts.buttons[i].Name) {
                case 'Export':
                case 'excel':
                    buttons.push(excelBtn);
                    break;
                default:
                    buttons.push({ text: opts.buttons[i].Text });
                    break;
            }
            //if (typeof opts.buttons[i] === 'string') {//字符串型(系统按钮)
            //    switch (opts.buttons[i]) {
            //        case 'Export':
            //        case 'excel':
            //            buttons.push(excelBtn);
            //            break;
            //        default:
            //            //buttons.push(opts.buttons[i]);
            //            break;
            //    }
            //} else {
            //    buttons.push(opts.buttons[i]);//对象型(自定义按钮)
            //}
        }
    } else {
        //buttons = [excelBtn];
        buttons = [];
    }
    if (buttons.length > 0) {
        var $operate = $('<div class="table-operate ue-clear"></div>');// style="display:none;"
        //var buttons = $pf.getTableToolbar(opts);
        for (var i = 0; i < buttons.length; i++) {
            var button = $('<a href="javascript:;" class="' + (buttons[i].icon || 'add') + '" id="' + me.id + '-exportExcel">' + buttons[i].text + '</a>');
            button.on('click', buttons[i].action);
            button.appendTo($operate);
        }
        me.before($operate);
    }
    _colIdxs = $pf.getTableColumnIdxs(me);
    drawCallback();

    result.tableApi = {
        row: function (rowDom) {
            return {
                data: function () {
                    //var cols = 
                    //var colIdxs = $pf.getTableColumnIdxs(selector);
                    //var colIdxs = $pf.getTableColumnIdxs(selector);

                    //me.find('thead tr td').each(function (i, ele) {
                    //    var td = $(ele);
                    //    var t = td.attr('field-name') || td.text();
                    //    cols.push(t);
                    //});
                    var row = $(rowDom);
                    var r = {};
                    for (var i = 0; i < _colIdxs.length; i++) {
                        r[_colIdxs[i]] = row.children()[i].innerText;
                    }
                    return r;
                }
            }
        }
    }
    return result;
};


/*
*统计图表(需要引用jqwidgets)
*/
jQuery.fn.pfPivotTable = function (opts) {
    var $pfTable = this;
    $pfTable.css('width', '800px');
    $pfTable.css('height', '400px');
    $pfTable.css('backgroundColor', 'white');

    var defaultOpts = jQuery.extend({
        //theme: 'classic',
        //source: pivotAdapter,
        treeStyleRows: true,
        autoResize: false,
        multipleSelectionEnabled: true
    }, opts || {});

    function newOpts() {
        var r = jQuery.extend({}, defaultOpts);
        //if (r.order instanceof Array) {
        //    r.order = r.order.slice(0);//数组型的成员要这样才不会因opts改变而改变
        //}
        return r;
    }
    opts = newOpts();

    var _url = '';
    var result = {};

    var $errorTableContainer = $('<div class="table"><div class="table-box"><table></table></div></div>')
    //var $errorTable = $('<table></table>');
    var $errorTable = $errorTableContainer.find('table');
    $pfTable.after($errorTableContainer);
    result.loadUrl = function (url, loadOpts) {
        loadOpts = loadOpts || {};
        var layerIdx = layer.load('正在查询请稍候');
        $.post(url, null, function (data) {
            if (data && data.Result !== false) {
                $errorTable.hide();
                $pfTable.show();
                _url = url;

                //var data = new Array();

                //var firstNames =
                //[
                //    "Andrew", "Nancy", "Shelley", "Regina", "Yoshi", "Antoni", "Mayumi", "Ian", "Peter", "Lars", "Petra", "Martin", "Sven", "Elio", "Beate", "Cheryl", "Michael", "Guylene"
                //];

                //var lastNames =
                //[
                //    "Fuller", "Davolio", "Burke", "Murphy", "Nagase", "Saavedra", "Ohno", "Devling", "Wilson", "Peterson", "Winkler", "Bein", "Petersen", "Rossi", "Vileid", "Saylor", "Bjorn", "Nodier"
                //];

                //var productNames =
                //[
                //    "Black Tea", "Green Tea", "Caffe Espresso"
                //];

                //var priceValues =
                //[
                //    "2.25", "1.5", "3.0", "3.3", "4.5", "3.6", "3.8", "2.5", "5.0", "1.75", "3.25", "4.0"
                //];

                //for (var i = 0; i < 500; i++) {
                //    var row = {};
                //    var productindex = Math.floor(Math.random() * productNames.length);
                //    var price = parseFloat(priceValues[productindex]);
                //    var quantity = 1 + Math.round(Math.random() * 10);

                //    row["firstname"] = firstNames[Math.floor(Math.random() * firstNames.length)];
                //    row["lastname"] = lastNames[Math.floor(Math.random() * lastNames.length)];
                //    row["productname"] = productNames[productindex];
                //    row["price"] = price;
                //    row["quantity"] = quantity;
                //    row["total"] = price * quantity;

                //    data[i] = row;
                //}

                var datafields = [];
                for (var i = 0; i < data.columns.length; i++) {
                    datafields.push({
                        name:data.columns[i].data,
                        type:data.columns[i].dataType
                    });
                }

                // create a data source and data adapter
                var source =
                {
                    //localdata: data,
                    localdata: data.data,
                    datatype: "array",
                    datafields: datafields
                    //[
                    //    { name: 'firstname', type: 'string' },
                    //    { name: 'lastname', type: 'string' },
                    //    { name: 'productname', type: 'string' },
                    //    { name: 'quantity', type: 'number' },
                    //    { name: 'price', type: 'number' },
                    //    { name: 'total', type: 'number' }
                    //]
                };

                var dataAdapter = new $.jqx.dataAdapter(source);
                dataAdapter.dataBind();

                opts = newOpts();
                // create a pivot adapter from the dataAdapter
                var pivotAdapter = new $.jqx.pivot(
                    dataAdapter,
                    {
                        pivotValuesOnRows: false,
                        totals: { rows: { subtotals: true, grandtotals: true }, columns: { subtotals: false, grandtotals: true } },
                        //rows: [{ dataField: 'firstname' }, { dataField: 'lastname' }],
                        //columns: [{ dataField: 'productname' }],
                        //values: [
                        //    { dataField: 'price', 'function': 'sum', text: 'sum', width: NamedNodeMap, formatSettings: { prefix: '$', decimalPlaces: 2 } },
                        //    { dataField: 'price', 'function': 'count', text: 'count' },
                        //    { dataField: 'price', 'function': 'average', text: 'average', formatSettings: { prefix: '$', decimalPlaces: 2 } }
                        //]

                        //rows: [{ dataField: '店主姓名' }, { dataField: '年龄段' }],//YJLevel功能的配置
                        //columns: [{ dataField: '当月级别' }],
                        //values: [
                        //    {
                        //        dataField: '人数', 'function': 'sum', text: '人数', width: NamedNodeMap
                        //        //, formatSettings: { prefix: '$', decimalPlaces: 0 } 
                        //    },
                        //]
                        rows:opts.rows,
                        columns: opts.columns,
                        values: opts.values
                    });
                delete opts.rows;
                delete opts.columns;
                delete opts.values;
                opts.source = pivotAdapter;
                if (typeof getJqxPivotLocalization == 'function') {
                    opts.localization = getJqxPivotLocalization('chs');
                }

                $pfTable.jqxPivotGrid(opts
                    //{
                    //    theme: 'classic',
                    //    source: pivotAdapter,
                    //    treeStyleRows: true,
                    //    autoResize: false,
                    //    multipleSelectionEnabled: true
                    //}
                    );
            } else {                
                var message = "没有数据";
                if (data && data.Message) { message = data.Message; }
                //$pf.warningPopups(message);
                $errorTable.html('<thead><tr><th style="border:1px solid #c1d3de;background-color:#E8F1F7;">提示</th></tr></thead><tbody><tr onclick="$pf.stopPropagation(arguments[0])"><td  onclick="$pf.stopPropagation(arguments[0])"  style="border:1px solid rgb(17, 17, 17);vertical-align:top;height:auto;">' + message + '</td></tr></tbody>');
                $pfTable.hide();
                $errorTable.show();
            }
            if (layerIdx) { layer.close(layerIdx); }
        });
    };
    return result;
};


/*
*perfect工具类，此类希望在所有项目中能版本唯一
*by wxj
*/
var $pf = $pf || {};

$pf.post = function (url, data, success, dataType) {
    var newSuccess = pfRequestSuccess(success);
    return $.post(url, data, newSuccess, dataType);
};
$pf.get = function (url, data, success, dataType) {
    var newSuccess = pfRequestSuccess(success);
    return $.get(url, data, newSuccess, dataType);
};

$pf.exporter = function (opt) {
    var self = this;
    var action = window.location.pathname.replace(/^(\/[^\/]+\/[^\/]+).*$/, '$1' + '/download');
    var defaultOptions = {
        //action: "/home/download",
        action: action,
        dataGetter: "api",
        dataAction: "",
        dataParams: {},
        titles: [[]],
        fileType: 'xls',
        compressType: 'none'
    };

    this.paging = function (page, rows) {
        self.params.dataParams.page = page;
        self.params.dataParams.rows = rows;
        return self;
    };

    this.compress = function () {
        self.params.compressType = 'zip';
        return self;
    };

    this.title = function (filed, title) {
        self.params.titles[filed] = title;
        return self;
    };

    this.download = function (suffix) {
        self.params.fileType = suffix || "xls";
        self.params.dataParams = JSON.stringify(self.params.dataParams);
        self.params.titles = JSON.stringify(self.params.titles);

        //创建iframe
        var downloadHelper = $('<iframe style="display:none;" id="downloadHelper"></iframe>').appendTo('body')[0];
        var doc = downloadHelper.contentWindow.document;
        if (doc) {
            doc.open();
            doc.write('')//微软为doc.clear();
            doc.writeln($pf.formatString("<html><body><form id='downloadForm' name='downloadForm' method='post' action='{0}'>", self.params.action));
            for (var key in self.params) doc.writeln($pf.formatString("<input type='hidden' name='{0}' value='{1}'>", key, self.params[key]));
            doc.writeln('<\/form><\/body><\/html>');
            doc.close();
            var form = doc.forms[0];
            if (form) {
                form.submit();
            }
        }
    };

    var initFromGrid = function (grid) {
        var options = grid.$element().datagrid('options');
        if (grid.treegrid)
            options.url = options.url || grid.treegrid('options').url;

        var titles = [[]], length = Math.max(options.frozenColumns.length, options.columns.length);
        for (var i = 0; i < length; i++)
            titles[i] = (options.frozenColumns[i] || []).concat(options.columns[i] || [])

        self.params = $.extend(true, {}, defaultOptions, {
            dataAction: options.url,
            dataParams: options.queryParams,
            titles: titles
        });
    };

    if (opt.$element)
        initFromGrid(opt);
    else
        self.params = $.extend(true, {}, defaultOptions, opt);

    return self;
};

/**
* 格式化字符串
* 用法:
.formatString("{0}-{1}","a","b");
*/
$pf.formatString = function () {
    for (var i = 1; i < arguments.length; i++) {
        var exp = new RegExp('\\{' + (i - 1) + '\\}', 'gm');
        arguments[0] = arguments[0].replace(exp, arguments[i]);
    }
    return arguments[0];
};

$pf.stringIsNullOrWhiteSpace = function (s) {
    return s === null || s === undefined || s.toString().replace(' ', '') === ''
};

$pf.isDecimal = function (value, precision) {
    if (value) {
        var sReg = "^[0-9]+\.{0,1}[0-9]";
        if (precision == null || precision == undefined) { sReg += "*"; }
        else { sReg += "{0," + precision + "}" }
        sReg += "$"
        var reg = new RegExp(sReg, "g");
        return reg.test(value);
    }
    return true;
};
$pf.isInt = function (value) {
    if (value) {
        return value.match(/^[0-9]+$/g)
    }
    return true;
};

$pf.objectToBool = function (value) {
    var r = null;
    if (value === '1' || value === 'true' || value === 'True') { r = true; }
    else if (value === '0' || value === 'false' || value === 'False') { r = false; }
    return r;
};

/*
*千分位
*/
$pf.thousandth = function (value) {
    var strValue = typeof value == 'number' ? value.toString() : value;
    if (strValue !== null && strValue !== undefined) {
        if (strValue.indexOf('.') > -1) {//有小数点时
            return strValue.replace(/(\d)(?=(\d{3})+\.)/g, '$1,');
        } else {
            return strValue.replace(/(\d)(?=(\d{3})+$)/g, '$1,');
        }
    }
    return strValue;
};

/*
*小数位数
*/
$pf.toFixed = function (value, decimalDigits) {
    if (decimalDigits === null || decimalDigits === undefined) { decimalDigits = 2; }
    if (typeof value == 'number') { return value.toFixed(decimalDigits); }
    else { return parseFloat(value).toFixed(decimalDigits); }
};

/**
* 格式化时间显示方式
* 用法:format="yyyy-MM-dd hh:mm:ss";
*/
$pf.formatTime = function (v, format) {
    if (!v) return "";
    var d = v;
    if (typeof v === 'string') {
        if (v.indexOf("/Date(") > -1)
            d = new Date(parseInt(v.replace("/Date(", "").replace(")/", ""), 10));
        else
            d = new Date(Date.parse(v.replace(/-/g, "/").replace("T", " ").split(".")[0]));//.split(".")[0] 用来处理出现毫秒的情况，截取掉.xxx，否则会出错
    }
    var o = {
        "M+": d.getMonth() + 1,  //month
        "d+": d.getDate(),       //day
        "h+": d.getHours(),      //hour
        "m+": d.getMinutes(),    //minute
        "s+": d.getSeconds(),    //second
        "q+": Math.floor((d.getMonth() + 3) / 3),  //quarter
        "S": d.getMilliseconds() //millisecond
    };
    if (/(y+)/.test(format)) {
        format = format.replace(RegExp.$1, (d.getFullYear() + "").substr(4 - RegExp.$1.length));
    }
    for (var k in o) {
        if (new RegExp("(" + k + ")").test(format)) {
            format = format.replace(RegExp.$1, RegExp.$1.length == 1 ? o[k] : ("00" + o[k]).substr(("" + o[k]).length));
        }
    }
    return format;
};

$pf.formatDate = function (value) {
    return $pf.formatTime(value, 'yyyy-MM-dd');
};

/*
*Data.getTime()相减之后的值转换为容易处理的对象
*/
$pf.getTimeSpan = function (date1, date2, ymd) {
    ymd = ymd || { hour: true, minute: true, second: true };
    var result = {};

    var s1 = date1.getTime();
    var s2 = date2.getTime();
    var total = (s2 - s1) / 1000;  //这里等到是秒
    var after = total;
    if (ymd.hour) {
        result.hour = parseInt(after / (60 * 60));//计算整数小时数
        after -= (result.hour * 60 * 60);//取得算出小时数后剩余的秒数
    };
    if (ymd.minute) {
        result.minute = parseInt(after / 60);//计算整数小时数
        after -= (result.minute * 60);//取得算出小时数后剩余的秒数
    };
    if (ymd.second) {
        result.second = parseInt(after);//计算整数秒数
        after -= result.second;//取得算出秒数后剩余的毫秒数
    };
    if (ymd.millisecond) {
        result.millisecond = after;
    };
    return result;
};

/*
阻止事件
*/
$pf.stopPropagation = function (event) {
    if (event.stopPropagation) {
        event.stopPropagation();
    } else {
        event.cancelBubble = true;
    }
};
/*
* 抛出事件
* param Array arrayParam  事件参数
*/
$pf.fireEvent = function (componentId, eventName, arrayParam) {
    $('#' + componentId).trigger(eventName, arrayParam);
};

/*
*返回jquery对象
*/
$pf.getJQ = function (dom) {
    if (dom instanceof jQuery) {
        return dom;
    } else {
        return jQuery(dom);
    }
};
/*
*后端生成的树型表格的展开方法(用于当json不能处理过大数据的情况)(此方法追求性能)
*/
$pf.expandTree = function (td) {
    //alert(1);
    //debugger;
    td = $pf.getJQ(td);
    //var td = $(td);
    var tr = td.parent('tr');
    var level = tr.attr('level');
    var expanded = tr.attr('expanded');
    if (level != null && level != undefined) {
        var iLevel = parseInt(level);

        var children = tr;
        while ((children = children.next('tr[level]')).length > 0) {
            var cLevel = parseInt(children.attr('level'));
            if (cLevel <= iLevel) { break; }
            if ((cLevel !== iLevel + 1) && expanded !== 'expanded') { continue; }//其实只下1层才需要展开,以前是所有子级展开是浪费的--wxj20180627
            if (expanded == 'expanded') {//展开->收起
                children.css('display', 'none');
                //$(children).hide();
            } else {//收起->展开
                children.css('display', 'table-row');
                var h = children.find('.hitarea');
                h.removeClass('hitarea-expanded');
                h.addClass('hitarea-closed');
                children.removeAttr('expanded');
                //$(children).show();
                //console.info(children.css('display'));
            }
        }
        var hitarea = td.find('.hitarea');
        if (expanded == 'expanded') {
            hitarea.removeClass('hitarea-expanded');
            hitarea.addClass('hitarea-closed');
        } else {
            hitarea.removeClass('hitarea-closed');
            hitarea.addClass('hitarea-expanded');
        }
    }
    if (expanded == 'expanded') {
        tr.removeAttr('expanded');
    } else {
        tr.attr('expanded', 'expanded');
    }
};

/*
*遍历末级叶节点,对应PFHelper里的TreeListItem结构
*/
$pf.eachLeaf = function (tree, action) {
    for (var i = 0; i < tree.Children.length; i++) {
        var a = tree.Children[i];
        if (a.Children.length > 0) {
            $pf.eachLeaf(a, action);
        }
        else {
            action(a);
        }
    }
};
/*
*获得所有末级叶Child的数量
*/
$pf.getAllLeafCount = function (tree, condition) {
    var total = 0;
    $pf.eachLeaf(tree, function (a) { if (condition == null || condition(a)) { total++; } });
    return total;
};
/*
*深度优先递归
*参数:T子项,int深度,T父节点
*/
$pf.eachChild = function (tree, action, depth) {
    if (depth === null || depth === undefined) { depth = 2; }
    //if (tree.Children !== null && tree.Children !== undefined) {
    for (var i = 0; i < tree.Children.length; i++) {
        var a = tree.Children[i];
        action(a, depth, tree); $pf.eachChild(a, action, depth + 1);
    }
    //}
    //tree.Children.ForEach(a => { action(a, depth, this); a.EachChild(action, depth + 1); });
};

/*
*获得最大深度(最小为1)
*/
$pf.getDepth = function (tree) {
    //debugger;
    var max = 1;
    $pf.eachChild(tree, function (a, b) { if (b > max) { max = b; } });
    return max;
};

/*
*上传文件(因为常用于批量查询,所以不统一加layer遮罩)
*/
$pf.uploadFile = function (fileInput, url, opts) {
    opts = opts || {};
    var success = opts.success;
    //var complete = opts.complete;
    var typeStr = opts.typeStr;
    var maxSize = opts.maxSize || 2097152;
    //var file = document.querySelector('input[type=file]').files[0];//IE10以下不支持
    var files = fileInput.files || fileInput[0].files;//IE10以下不支持,当为jq对象时要拿第一个
    function errorReturn() {
        if (typeof error === 'function') {
            error();
        }
    }
    if (files !== null && files !== undefined && files.length > 0) {

        var file = files[0];
        //var typeStr = "image/jpg,image/png,image/gif,image/jpeg";

        if (typeStr === null || typeStr === undefined || typeStr.indexOf(file.type) >= 0) {
            //document.getElementById('test1').value = file.name;
            if (file.size > maxSize) {
                alert("上传的文件不能大于2M");
                errorReturn();
            } else {
                var layerIdx = layer.load('正在上传请稍候');
                var fd = new FormData();
                fd.append('file1', file);//上传的文件： 键名，键值
                //var url = path;//接口
                url = url ? url : '';
                var XHR = null;
                if (window.XMLHttpRequest) {
                    // 非IE内核
                    XHR = new XMLHttpRequest();
                } else if (window.ActiveXObject) {
                    // IE内核，这里早期IE版本不同，具体可以查下
                    XHR = new ActiveXObject("Microsoft.XMLHTTP");
                } else {
                    XHR = null;
                }
                if (XHR) {
                    XHR.open("POST", url);
                    XHR.onreadystatechange = function () {
                        if (XHR.readyState == 4) {
                            //if (typeof complete === 'function') {
                            //    complete();
                            //}
                            if (layerIdx) { layer.close(layerIdx); }
                            if (XHR.status == 200) {
                                var resultValue = XHR.responseText;
                                var data = JSON.parse(resultValue);
                                if (typeof success === 'function') {
                                    success(data);
                                }
                                XHR = null;
                            }
                        }
                    }
                    XHR.send(fd);
                }
            }
        } else {
            alert("请上传格式为" + typeStr + "的图片");
            errorReturn();
        }
    }
    //else if (typeof complete === 'function') {
    //    complete();
    //}
};

/*
获得月份的英文简称
*/
$pf.getEnMonthByNum = function (num) {
    switch (num) {
        case 1:
            return 'Jan'
        case 2:
            return 'Feb'
        case 3:
            return 'Mar'
        case 4:
            return 'Apr'
        case 5:
            return 'May'
        case 6:
            return 'Jun'
        case 7:
            return 'Jul'
        case 8:
            return 'Aug'
        case 9:
            return 'Sep'
        case 10:
            return 'Oct'
        case 11:
            return 'Nov'
        case 12:
            return 'Dec'
        default:
            return ''
    }
};


/*
* 获取url中的参数
*/
$pf.getRequest = function () {
    var url = location.search; // 获取url中含"?"符后的字串

    var theRequest = {};

    if (url.indexOf('?') !== -1) {
        var str = url.substr(1);

        var strs = str.split('&');

        for (var i = 0; i < strs.length; i++) {
            theRequest[strs[i].split('=')[0]] = unescape(strs[i].split('=')[1]);
        }
    }

    return theRequest;
};

/*
*设置url参数
*/
$pf.setUrlParams = function (url, arr) {
    if (url.indexOf('?') < 0) {
        url += '?';
    } else {
        var lc = url[url.length - 1];
        if (lc !== '?' && lc !== '&') {
            url += '&';
        }
    }

    function setParam(sUrl, name, val) {
        if (val instanceof Array) {
            for (var i = 0; i < val.length; i++) {
                sUrl += (name + '=' + val[i] + '&');
            }
        } else {
            sUrl += (name + '=' + val + '&');
        }
        return sUrl;
    }
    function removeSameParam(sUrl, pName) {//移除url中已经存在的同名参数,已考虑 xx[]的情况
        var patt1 = new RegExp("([\&\?]{1})" + pName + "[\\[\\]]{0,2}\=[^\&]*[\&]{0,1}", "g");
        return sUrl.replace(patt1, '$1');
    }
    //到这里url格式为 xx? 或者 xx?xx&
    if (arr instanceof Array) {
        for (var i = 0; i < arr.length; i++) {//考虑到有数组的情况,必需全部移除再设置
            url = removeSameParam(url, arr[i].name);
        }
        for (var i = 0; i < arr.length; i++) {
            url = setParam(url, arr[i].name, arr[i].value);
        }
    } else {//object
        for (var i in arr) {//考虑到有数组的情况,必需全部移除再设置
            if (arr.hasOwnProperty(i)) {
                url = removeSameParam(url, i);
            }
        }
        for (var i in arr) {
            if (arr.hasOwnProperty(i)) {
                url = setParam(url, i, arr[i]);
            }
        }
    }
    if (url[url.length - 1] === '&') { url = url.substr(0, url.length - 1); }
    return url;
};

/*
*此方法待删除,请使用getTableColumnDataIdxs(应该不用删除,后来发现子列没有返回field-name,第一行是对的--benjamin20190428)
*拿table的列索引集合,考虑多表头的情况(对于隐藏列,暂当其不生成到dom)
*/
$pf.getTableColumnIdxs = function (tableDom) {
    var me = $(tableDom);
    var head = me.find('thead');
    var trs = head.children();
    var r = {};// 格式如{1:'',2:''} 注意,为了写法规范,这里用对象,最后转为数组
    var unGetCols = [];//格式如[3,4] 从第一个tr里找列,如果colspan不为1,就从第二个tr开始找
    //var hideCols = [];如果有隐藏列,用这个--wxjlatertodo
    var i = 0;
    $(trs[0]).children().each(function (idx, ele) {//遍历第一个tr里的td
        var htd = $(ele);
        var colspan = parseInt(htd.attr('colspan') || 1);
        if (colspan === 1) {
            r[i] = htd.attr('field-name') || htd.text();
        } else {
            for (var j = i; j < i + colspan; j++) {
                unGetCols.push(j);
            }
        }
        i += colspan;
    });
    if (unGetCols.length > 0) {//如果是多表头
        for (l = 1; l < trs.length; l++) {
            //var count = 0;
            var sIdx = unGetCols[0];
            //if (trs.attr('visible')) { hideCols.add(); continue; }//如果有隐藏列,用这个(未完成)--wxjlatertodo
            $(trs[l]).children().each(function (idx, ele) {
                var htd = $(ele);
                var colspan = parseInt(htd.attr('colspan') || 1);
                if (colspan === 1) {
                    //r[sIdx] = htd.text();//这里应该是搞错了,因为第一层也是用的field-name--benjamin20190428
                    r[sIdx] = htd.attr('field-name') || htd.text();
                    unGetCols.splice(unGetCols.indexOf(sIdx), 1);
                }
                sIdx += colspan;
            });
            if (unGetCols.length < 1) { break; }
        }
    }
    var rArr = [];//格式如 ['col1','col2']
    for (var k = 0; k < i; k++) {//在这里i是总列数
        rArr.push(r[k])
    }
    return rArr;
};

///*
//*和getTableColumnIdxs是一样的,因为发现getTableColumnIdxs返回的是td的text,而不是data,这样应该是错的,
//*但不是很确定,因此新开一个方法,getTableColumnIdxs在以后有可能要删除
//*/
//$pf.getTableColumnDataIdxs = function (tableDom) {
//    var me = $(tableDom);
//    var head = me.find('thead');
//    var trs = head.children();
//    var r = {};// 格式如{1:'',2:''} 注意,为了写法规范,这里用对象,最后转为数组
//    var unGetCols = [];//格式如[3,4] 从第一个tr里找列,如果colspan不为1,就从第二个tr开始找
//    //var hideCols = [];如果有隐藏列,用这个--wxjlatertodo
//    var i = 0;
//    $(trs[0]).children().each(function (idx, ele) {//遍历第一个tr里的td
//        var htd = $(ele);
//        var colspan = parseInt(htd.attr('colspan') || 1);
//        if (colspan === 1) {
//            r[i] = htd.attr('field-name') || htd.text();
//        } else {
//            for (var j = i; j < i + colspan; j++) {
//                unGetCols.push(j);
//            }
//        }
//        i += colspan;
//    });
//    if (unGetCols.length > 0) {//如果是多表头
//        for (l = 1; l < trs.length; l++) {
//            //var count = 0;
//            var sIdx = unGetCols[0];
//            //if (trs.attr('visible')) { hideCols.add(); continue; }//如果有隐藏列,用这个(未完成)--wxjlatertodo
//            $(trs[l]).children().each(function (idx, ele) {
//                var htd = $(ele);
//                var colspan = parseInt(htd.attr('colspan') || 1);
//                if (colspan === 1) {
//                    r[sIdx] = htd.text();
//                    unGetCols.splice(unGetCols.indexOf(sIdx), 1);
//                }
//                sIdx += colspan;
//            });
//            if (unGetCols.length < 1) { break; }
//        }
//    }
//    var rArr = [];//格式如 ['col1','col2']
//    for (var k = 0; k < i; k++) {//在这里i是总列数
//        rArr.push(r[k])
//    }
//    return rArr;
//};

/*
*绑定table的列点击事件，因为列是动态生成且可变的，所以每次load complete之后重新绑定是有必要的
*/
$pf.bindTableColumnClick = function (table, columnTitle, action) {
    //debugger;
    var colIdxs = $pf.getTableColumnIdxs(table);
    var idx = colIdxs.indexOf(columnTitle);
    if (idx !== null && idx !== undefined) {
        var $cell = table.find('tbody tr td:nth-child(' + (idx + 1) + ')');
        $cell.unbind('click', action);
        $cell.bind('click', action);
        $cell.css('textDecoration', 'underline');
        $cell.css('cursor', 'pointer');
    }
};

$pf.mergeTableCell = function (table, columnTitle) {
    var colIdxs = $pf.getTableColumnIdxs(table);
    var idx = colIdxs.indexOf(columnTitle);
    //var cells = table.find('tbody tr td');
    var cells = table.find('tbody tr td:nth-child(' + (idx + 1) + ')');
    var lastValue = '';
    var cellGroup = {};
    cells.each(function (index, element) {
        var $element = $(element);
        var text = $element.text();
        if (cellGroup[text] === null || cellGroup[text] === undefined) {
            cellGroup[text] = 0;
        }
        cellGroup[text] += 1;
        //if (lastValue !== $element.text()) {
        //    $element.attr('rowspan', table.find('tbody tr td'))
        //} else {
        //    $element.css('display','none');
        //}
        //lastValue = $(element).text();
    });
    cells.each(function (index, element) {
        var $element = $(element);
        var text = $element.text();
        if (lastValue !== text && cellGroup[text] !== null && cellGroup[text] !== undefined) {
            $element.attr('rowspan', cellGroup[text]);
        } else {
            $element.css('display', 'none');
        }
        lastValue = text;
    });
    //for (var i in cellGroup) {
    //    if (cellGroup.hasOwnProperty(i)) {

    //    }
    //}
};

/*
* 复制表头的宽度(为了解决锁表头时,表头列宽不一致的问题)
* setTableWidth:bool 是否设置table宽度(当dst的列比src的列少时,有必要这样)
*/
$pf.copyTableHeadWidth = function (srcHead, dstHead, setTableWidth) {
    var width = 0;
    for (var i = 0; i < dstHead.find('tr').length; i++) {
        var tr = dstHead.find('tr').eq(i);
        var trSrc = srcHead.find('tr').eq(i);
        for (var j = 0; j < tr.find('th').length; j++) {
            var th = tr.find('th').eq(j);//dst
            var thSrc = trSrc.find('th').eq(j);
            var rect = thSrc[0].getBoundingClientRect();
            if (setTableWidth && i === 0) {
                width += rect.width;
            }
            //debugger;
            th.css('minWidth',
                (rect.width
                - 1//border
                - parseInt(thSrc.css('paddingLeft').replace('px'))
                - parseInt(thSrc.css('paddingRight').replace('px'))
                ) + 'px'
                );
        }
    }
    if (setTableWidth) {
        dstHead.parents('table:eq(0)').width(width + 'px');
    }
};

/*
*月份相减,格式如 2017.01
*/
$pf.monthSubtract = function (bigger, smaller) {
    var b = bigger.split('.');
    var s = smaller.split('.');
    return (parseInt(b[0]) - parseInt(s[0])) * 12
        + parseInt(b[1]) - parseInt(s[1]);
};

$pf.setFormValues = function (form, values) {
    var fields = form.find('input[type=text],input[type=select],input[type=number]');
    fields.each(function (index, element) {
        var me = $(element);
        var v = values[element.name];
        if (v !== undefined) { me.val(v); }
    });
};

$pf.resetForm = function (form) {
    form[0].reset();
    //下拉控件的值清除
    form.find('select.iselect').each(function (index, element) {
        var me = $(this);
        var sp = me.next();
        //select元素reset后其实是选中了第一个元素
        //if (sp.hasClass('iselwrap-val')) { sp.text(me.find("option:first").text()) }//reset是回到页面加载时的form状态才对
        if (sp.hasClass('iselwrap-val')) { sp.text(me.find("option:selected").text()) }
    });
    form.find('.pf-fileupload').each(function (index, element) {
        var me = $(this);
        //debugger;
        //var fileF = me.find('input[type=file]');
        //form[0].reset()已经把file清空了
        //if (fileF.val() != "") {    //当file有地址才进行清空  
        //    fileF.remove();     //移除当前file  
        //    fileF.val('');
        //}
        me.find('span').html('');
    });
};

$pf.disableField = function (arg) {
    for (var i = 0; i < arguments.length; i++) {
        var field = arguments[i];
        if (field[0].nodeName === 'INPUT') {
            if (field.attr('type') === 'radio') {
                field.filter(function () { return !($(this).is(':checked')); }).attr("disabled", 'disabled');
            } else {
                field.attr('readonly', 'readonly');
                if (field.hasClass('Wdate')) {
                    field.removeAttr('onclick');
                }
            }
        } else if (field[0].nodeName === 'SELECT') {
            //field.attr('readonly', 'readonly');//select元素的readonly属性无效
            field.attr('disabled', 'disabled');
            //由于禁用后不会自动提交值,不方便,所以用隐藏字段保存值
            var hideFId = field[0].getAttribute('id') + '_hidden';
            var hideF = document.getElementById(hideFId);
            if (hideF === null || hideF === undefined) {
                hideF = document.createElement("input");
                hideF.setAttribute('type', 'hidden');
                hideF.setAttribute('id', hideFId)
                hideF.name = field[0].name;
                field[0].parentNode.insertBefore(hideF, field[0]);
            }
            hideF.value = field[0].value;
        }
    }
};

$pf.watermark = function (settings) {
    //debugger;
    //默认设置
    var defaultSettings = {
        watermark_txt: "text",
        watermark_x: 20,//水印起始位置x轴坐标
        watermark_y: 20,//水印起始位置Y轴坐标
        watermark_rows: 20,//水印行数
        watermark_cols: 20,//水印列数
        watermark_x_space: 100,//水印x轴间隔
        watermark_y_space: 50,//水印y轴间隔
        watermark_color: '#aaa',//水印字体颜色
        watermark_alpha: 0.4,//水印透明度
        watermark_fontsize: '15px',//水印字体大小
        watermark_font: '微软雅黑',//水印字体
        watermark_width: 210,//水印宽度
        watermark_height: 80,//水印长度
        watermark_angle: 15//水印倾斜度数
    };
    //采用配置项替换默认值，作用类似jquery.extend
    if (arguments.length === 1 && typeof arguments[0] === "object") {
        var src = arguments[0] || {};
        for (key in src) {
            if (src[key] && defaultSettings[key] && src[key] === defaultSettings[key])
                continue;
            else if (src[key])
                defaultSettings[key] = src[key];
        }
    }

    var oTemp = document.createDocumentFragment();

    //获取页面最大宽度
    var page_width = Math.max(document.body.scrollWidth, document.body.clientWidth);
    var cutWidth = page_width * 0.0150;
    page_width = page_width - cutWidth;
    //获取页面最大高度
    var page_height = Math.max(document.body.scrollHeight, document.body.clientHeight) - 100; // + 450//原版加450,会导致页面撑长
    // var page_height = document.body.scrollHeight+document.body.scrollTop;
    //如果将水印列数设置为0，或水印列数设置过大，超过页面最大宽度，则重新计算水印列数和水印x轴间隔
    if (defaultSettings.watermark_cols == 0 || (parseInt(defaultSettings.watermark_x + defaultSettings.watermark_width * defaultSettings.watermark_cols + defaultSettings.watermark_x_space * (defaultSettings.watermark_cols - 1)) > page_width)) {
        defaultSettings.watermark_cols = parseInt((page_width - defaultSettings.watermark_x + defaultSettings.watermark_x_space) / (defaultSettings.watermark_width + defaultSettings.watermark_x_space));
        defaultSettings.watermark_x_space = parseInt((page_width - defaultSettings.watermark_x - defaultSettings.watermark_width * defaultSettings.watermark_cols) / (defaultSettings.watermark_cols - 1));
    }
    //如果将水印行数设置为0，或水印行数设置过大，超过页面最大长度，则重新计算水印行数和水印y轴间隔
    if (defaultSettings.watermark_rows == 0 || (parseInt(defaultSettings.watermark_y + defaultSettings.watermark_height * defaultSettings.watermark_rows + defaultSettings.watermark_y_space * (defaultSettings.watermark_rows - 1)) > page_height)) {
        defaultSettings.watermark_rows = parseInt((defaultSettings.watermark_y_space + page_height - defaultSettings.watermark_y) / (defaultSettings.watermark_height + defaultSettings.watermark_y_space));
        defaultSettings.watermark_y_space = parseInt(((page_height - defaultSettings.watermark_y) - defaultSettings.watermark_height * defaultSettings.watermark_rows) / (defaultSettings.watermark_rows - 1));
    }
    var x;
    var y;
    for (var i = 0; i < defaultSettings.watermark_rows; i++) {
        y = defaultSettings.watermark_y + (defaultSettings.watermark_y_space + defaultSettings.watermark_height) * i;
        for (var j = 0; j < defaultSettings.watermark_cols; j++) {
            x = defaultSettings.watermark_x + (defaultSettings.watermark_width + defaultSettings.watermark_x_space) * j;

            var mask_div = document.createElement('div');
            mask_div.id = 'mask_div' + i + j;
            mask_div.className = 'mask_div';
            mask_div.appendChild(document.createTextNode(defaultSettings.watermark_txt));
            //设置水印div倾斜显示
            mask_div.style.webkitTransform = "rotate(-" + defaultSettings.watermark_angle + "deg)";
            mask_div.style.MozTransform = "rotate(-" + defaultSettings.watermark_angle + "deg)";
            mask_div.style.msTransform = "rotate(-" + defaultSettings.watermark_angle + "deg)";
            mask_div.style.OTransform = "rotate(-" + defaultSettings.watermark_angle + "deg)";
            mask_div.style.transform = "rotate(-" + defaultSettings.watermark_angle + "deg)";
            mask_div.style.visibility = "";
            mask_div.style.position = "absolute";
            mask_div.style.left = x + 'px';
            mask_div.style.top = y + 'px';
            mask_div.style.overflow = "hidden";
            mask_div.style.zIndex = "9999";
            mask_div.style.pointerEvents = 'none';//pointer-events:none  让水印不遮挡页面的点击事件
            //mask_div.style.border="solid #eee 1px";
            mask_div.style.opacity = defaultSettings.watermark_alpha;
            mask_div.style.fontSize = defaultSettings.watermark_fontsize;
            mask_div.style.fontFamily = defaultSettings.watermark_font;
            mask_div.style.color = defaultSettings.watermark_color;
            mask_div.style.textAlign = "center";
            mask_div.style.width = defaultSettings.watermark_width + 'px';
            mask_div.style.height = defaultSettings.watermark_height + 'px';
            mask_div.style.display = "block";
            oTemp.appendChild(mask_div);
        };
    };
    document.body.appendChild(oTemp);
};

$pf.clearIframe = function (frame) {
    //var frame = $('iframe', context).add(parent.$('iframe', context));
    if (frame.length > 0) {
        //frame[0].contentWindow.document.write('');
        frame[0].contentWindow.document.clear();
        frame[0].contentWindow.close();
        //frame.remove();
        //if ($.browser.msie) {
        //    CollectGarbage();旧版本ie才有用
        //}
    }
};

/*
*进度查询的请求
*@interval int 时间间隔
*/
$pf.progressPost = function (url, data, success, stopCallback, interval, dataType) {
    var newSuccess = function (data, textStatus, jqXHR) {
        var stop = true;
        try {
            success(data, textStatus, jqXHR);
            stop = stopCallback(data, textStatus, jqXHR) !== true;
        } catch (e) { }//以防网络错误造成回调报错而不继续执行
        if (stop) {
            setTimeout(function () {
                $pf.progressPost(url, data, success, stopCallback, interval, dataType);
            }, interval);
        }

    };
    return $pf.post(url, data, newSuccess, dataType);
};

/*
*复制dom的border,因为jquery在ie中,css('borderRight')取不到值
*dir:{up:true,right:true,...} 复制的方向,默认全部
*/
$pf.copyDomBorder = function (srcDom, dstDom, dir) {//查询连线网某个点的线条形状
    dir = dir || { up: true, right: true, down: true, left: true };
    var s = '';
    if (dir.right) {
        s = srcDom.css('borderRight');
        if ($pf.stringIsNullOrWhiteSpace(s)) {//ie中
            dstDom.css('borderRightWidth', srcDom.css('borderRightWidth'));
            dstDom.css('borderRightStyle', srcDom.css('borderRightStyle'));
            dstDom.css('borderRightColor', srcDom.css('borderRightColor'));
            //s = srcDom.css('borderRightWidth') + ' ' + srcDom.css('borderRightStyle') + ' ' + srcDom.css('borderRightColor');
        } else {
            dstDom.css('borderRight', s);
        }
    }
    //if (dir.up && n.right && n.down) { return urd; }
    //if (dir.up && n.down) { return ud; }
    //if (dir.up && n.right) { return ur; }
};
/*
*3维空间内，点到线段的距离，来自：https://blog.csdn.net/u012138730/article/details/79779996
*[0]:x [1]:y [2]:z ,当z都为0时，可以当作2维平面使用
*p和q为线段的两个端点
*/
$pf.distancePtSeg = function (pt, p, q) {
    var pqx = q[0] - p[0];
    var pqy = q[1] - p[1];
    var pqz = q[2] - p[2];
    var dx = pt[0] - p[0];
    var dy = pt[1] - p[1];
    var dz = pt[2] - p[2];
    var d = pqx * pqx + pqy * pqy + pqz * pqz;      // qp线段长度的平方
    var t = pqx * dx + pqy * dy + pqz * dz;         // p pt向量 点积 pq 向量（p相当于A点，q相当于B点，pt相当于P点）
    if (d > 0)         // 除数不能为0; 如果为零 t应该也为零。下面计算结果仍然成立。                   
        t /= d;    // 此时t 相当于 上述推导中的 r。
    if (t < 0)
        t = 0;     // 当t（r）< 0时，最短距离即为 pt点 和 p点（A点和P点）之间的距离。
    else if (t > 1)
        t = 1;     // 当t（r）> 1时，最短距离即为 pt点 和 q点（B点和P点）之间的距离。

    // t = 0，计算 pt点 和 p点的距离; t = 1, 计算 pt点 和 q点 的距离; 否则计算 pt点 和 投影点 的距离。
    dx = p[0] + t * pqx - pt[0];
    dy = p[1] + t * pqy - pt[1];
    dz = p[2] + t * pqz - pt[2];
    return dx * dx + dy * dy + dz * dz;
}
/*
*计算点到range的距离，其实就是点到矩形(left,top,width,height)的距离
*x,y: 点的坐标
*range: 范围，可理解为矩形
*坐标方向: 网页的坐标方向，即: 正x(右) 正y(下)
*/
$pf.getDistanceBetweenPointAndRect = function (x, y, inRect) {
    // var rects= inRect instanceof Array?inRect:[inRect];//DOMRectList不是数组
    var rects = (inRect.length && typeof inRect.length == 'number') ? inRect : [inRect];

    var result = -1;
    //debugger;
    for (var i = 0; i < rects.length; i++) {
        var rect = rects[i];
        var xDistance = 0;
        var yDistance = 0;

        if (x < rect.left) {
            xDistance = rect.left - x;
        } else if (x > (rect.left + rect.width)) {
            xDistance = x - (rect.left + rect.width);
        } else {
            xDistance = 0;
        }

        if (y < rect.top) {
            yDistance = rect.top - y;
        } else if (y > (rect.top + rect.height)) {
            yDistance = y - (rect.top + rect.height);
        } else {
            yDistance = 0;
        }

        var d = Math.sqrt(Math.pow(xDistance, 2) + Math.pow(yDistance, 2));
        if (i === 0 || d < result) {
            result = d;
        }
    }
    return result;
};
/*
*找到最接近某个点的子元素
*/
$pf.findNearestChild = function (next, x, y) {
    //debugger;
    if (next.childNodes === undefined || next.childNodes === null || next.childNodes.length < 1) {
        //console.info(1);
        return next;
    } else {
        var child = next.childNodes;

        var nearestDistance = -1;//最近距离
        var nearestPos = -1;//最近距离
        for (var i = 0; i < child.length; i++) {
            var range = document.createRange();
            range.selectNode(child[i]);
            var rect = range.getClientRects();
            if (rect.length < 1) {
                continue;
            }
            //console.info(rect);
            d = $pf.getDistanceBetweenPointAndRect(x, y, rect);
            if (nearestDistance === -1 || d < nearestDistance) {
                nearestDistance = d;
                nearestPos = i;
            }
        }
        if (nearestPos === -1) { return next; }//当child都是一个空格的textNode时，getClientRects的length为0--benjamin20190605
        return $pf.findNearestChild(next.childNodes[nearestPos]);
        //return child[nearestPos];
    }
};
/*
*调用时next可以留空,暂不接收jquery对象
*由于有document.elementFromPoint(x,y)但没有nodeFrom,所以需要此方法
*/
$pf.selectNodeByXY = function (x, y//, next
    ) {
    var next = $pf.findNearestChild(document.elementFromPoint(x, y), x, y);
    //debugger;
    var nearestDistance = -1;//最近距离
    var nearestPos = 0;//最近距离
    var l = next.length || 0;
    var range = document.createRange();
    range.selectNode(next);
    for (var i = 0; i <= l; i++) {
        range.setStart(next, i);
        range.setEnd(next, i);
        var rect = range.getClientRects();
        if (rect.length < 1) {
            continue;
        }
        d = $pf.getDistanceBetweenPointAndRect(x, y, rect);
        //console.info(rect);
        if (nearestDistance === -1 || d < nearestDistance) {
            nearestDistance = d;
            nearestPos = i;
        }
    }
    //console.info({ isTextNode: next.nodeType === 3, node: next, pos: nearestPos });
    return { isTextNode: next.nodeType === 3, node: next, pos: nearestPos };

};

/*
*保存本地cache数组（localStorage.setItem的扩展）
*param arr 类型Array
*/
$pf.setLocalStorage = function (key, arr) {
    if (arr === null || arr === undefined || arr.length < 1) {
        localStorage.removeItem(key);
    } else {
        //localStorage.setItem(key, arr.toString());
        localStorage.setItem(key, JSON.stringify(arr));
    }
};
$pf.getLocalStorage = function (key) {
    var s = localStorage.getItem(key);
    if (s !== null && s !== '') {//空字符串split后会有length:1
        //return s.split(',');
        return JSON.parse(s);
    } else {//没cache就全选
        return null;
    }
};


if (jQuery !== null && jQuery !== undefined) {
    /*
    *把post方法绑定到a按钮上(并防止重复点击
    *a元素当按钮有一个好处,就是宽度可以根据文字自适应
    */
    jQuery.fn.pfPost = function (url, data, success, dataType) {
        var me = this;
        if (me[0].nodeName === 'A' || me[0].nodeName === 'INPUT') {
            if (me.attr('disabled') !== 'disabled') {
                me.attr('disabled', 'disabled');
                var jqxhr = $pf.post(url, data, success, dataType);
                if (typeof jqxhr.complete == 'function') {//jQuery 1.5才有complete方法
                    jqxhr.complete(function () { me.removeAttr('disabled'); });
                } else if (typeof jqxhr.done == 'function') {//jQuery 3.3.1
                    jqxhr.done(function () { me.removeAttr('disabled'); });
                }
                return jqxhr;
            }
        }
        return null;
    };
}

$(document).ready(function () {
    $('.pf-fileupload input[type=file]').change(function (v) {//文件上传
        var $fInput = $(this);
        var files = $fInput[0].files;
        if (files !== null && files !== undefined && files.length > 0) {
            //console.info($fInput.parent()[0].innerText);
            $fInput.parent().find('span').text(files[0].name);
        }
    });
    //debugger;
    var chooseLabel = $('span.choose span.text');
    chooseLabel.css('cursor', 'default');//pointer
    chooseLabel.click(function () {//RadioButton点label时把input选上,增加体验
        //debugger;
        var me=$(this);
        var p =me.parent();
        p.find('input[type=radio]').click();
        p.find('input[type=checkbox]').click();
    });
});